#!/usr/bin/env bash
# Copyright (c) 2021 maminjie <canpool@163.com>
# SPDX-License-Identifier: MulanPSL-2.0

method_def sync

usage_sync() {
printf "sync: Sync branch code of repo

usage:
    ${PROG} sync subcmd [args...] [options]

subcmd:
$(module_usage_subcmd sync)

args:
    Type '${PROG} sync help <subcmd>' for help on a specific subcmd details.

options:
    -h, --help          Show this help message and exit
    -s, --source        The source branch of repo
    -t, --target        The target branch of repo
    -r, --repo          The remote repo name
    -o, --owner         The owner of remote repo
        --repo-list     The remote repo name list
        --branch-list   The branch list of remote repo
"
}

# do_sync subcmd [args...] [options]
do_sync() {
    local ARGS=$(getopt -o "hs:t:r:o:" \
        -l "help,source:,target:,repo:,owner:,repo-list:,branch-list:" \
        -n "sync" -- "$@")
    eval set -- "${ARGS}"

    local sourcebr=""
    local targetbr=""
    local repo=""
    local owner=""
    local repolist=""
    local branchlist=""

    while true; do
        case "${1}" in
            -h|--help)
                usage_sync; exit
                ;;
            -s|--source)
                shift; sourcebr="${1}"; shift
                ;;
            -t|--target)
                shift; targetbr="${1}"; shift
                ;;
            -r|--repo)
                shift; repo="${1}"; shift
                ;;
            -o|--owner)
                shift; owner="${1}"; shift
                ;;
            --repo-list)
                repolist="${2}"; shift 2
                ;;
            --branch-list)
                branchlist="${2}"; shift 2
                ;;
            --)
                shift; break
                ;;
        esac
    done

    if [ $# -eq 0 ]; then
        usage_sync; exit
    fi

    local cmd="$(__sync_get_subcmd "$1")"
    case "${cmd}" in
        "check")
            sync_do_check $owner $repo
            ;;
        "log"|"diff")
            sync_do_"$1" "$sourcebr" "$targetbr"
            ;;
        "help")
            shift; sync_do_help "$@"
            ;;
        "version")
            sync_do_version "$owner" "$repolist" "$branchlist"
            ;;
        *)
            usage_sync
            ;;
    esac
}

sync_usage_help() {
    module_usage_help sync
}

# sync_do_help subcmd
sync_do_help() {
    module_do_help sync "$1"
}

__sync_get_subcmd() {
    local cmd=""
    case "${1}" in
        "h"|"help")
            cmd="help"
            ;;
        "c"|"check")
            cmd="check"
            ;;
        "log")
            cmd="log"
            ;;
        "d"|"diff")
            cmd="diff"
            ;;
        "v"|"version")
            cmd="version"
            ;;
        *)
            ;;
    esac
    echo "$cmd"
}

sync_usage_check() {
printf "check (c): Check package versions of different branches

usage:
    ${PROG} sync check [-o|--owner OWNER] [-r|--repo REPO]

params:
    -o, --owner     (optional) The owner or remote repo, defalut is the configured gitee id
    -r, --repo      (optional) The remote repo name, default is local repo name

If the owner and repo are specified, the versions of different branches of the remote repo will be detected,
otherwise the versions of the local repo (the current directory must be a git repo) or
different branches of the personal remote repo will be detected.

"
}

# sync_do_check [owner] [repo]
sync_do_check() {
    if [ $# -gt 0 ]; then
        sync_check_remote_version "$@"
    else
        sync_check_version
    fi
}

# branch, specdata
__sync_print_version_info() {
    local __specdata="$2"
    local version=$(spec_get_version "$__specdata")
    local release=$(spec_get_release "$__specdata")
    printf "%s,%s,%s\n" "$1" "$version" "$release"
}

sync_check_version() {
    local curbranch=$(git_curbranch)
    if [ -z "$curbranch" ]; then
        exit
    fi

    local repo="${PWD##*/}"
    local spec="$repo.spec"
    local curspec=$(ls --format=single-column *.spec 2>/dev/null | head -n 1)
    if [[ -n "$curspec" && "$spec" != "$curspec" ]]; then
        spec="$curspec"
        repo="${spec%.*}"
    fi
    local branches=$(git branch -a | grep "remotes/origin" | grep -v "HEAD" | sed 's/^\s\+remotes\/origin\///g')
    {
    printf "%s,%s,%s\n" "Branch" "Version" "Release"
    printf "%s,%s,%s\n" "------" "------" "------"
    for branch in $branches; do
        # get from local
        local specdata="$(git show $branch:$spec 2>/dev/null)"
        local __branch="$branch"
        if [ "$curbranch" = "$branch" ]; then
            __branch="*$branch"
        fi
        if [ -z "$specdata" ]; then
            # get from remote
            local id=$(setting_get gitee id)
            local specdata="$(gec_get_contents "$id" "$repo" "$spec" "$branch")"
            if [ -z "$specdata" ]; then
                printf "%s,,\n" "$__branch"
            else
                __sync_print_version_info "$__branch" "$specdata"
            fi
        else
            __sync_print_version_info "$__branch" "$specdata"
        fi
    done
    } | format_column ","
}

# sync_check_remote_version owner repo
sync_check_remote_version() {
    if [ $# -ne 2 ]; then
        sync_usage_check; exit
    fi
    local owner="$1"
    local repo="$2"
    local branches=$(gec_get_branches "$owner" "$repo")
    if [ -z "$branches" ]; then
        log_warn "No branch in $owner/$repo"; exit
    fi
    {
    printf "%s,%s,%s\n" "Branch" "Version" "Release"
    printf "%s,%s,%s\n" "------" "------" "------"
    local __branch=""
    for branch in $branches; do
        local specdata="$(gec_get_contents "$owner" "$repo" "$repo.spec" "$branch")"
        if [ -z "$__branch" ]; then
            __branch="*$branch" # first is current branch
        else
            __branch="$branch"
        fi
        if [ -z "$specdata" ]; then
            printf "%s,,\n" "$__branch"
        else
            __sync_print_version_info "$__branch" "$specdata"
        fi
    done
    } | format_column ","
}

sync_usage_log() {
printf "log: Show the commit list of the source branch ahead of/different from the target branch

usage:
    ${PROG} sync log -s|--source SOURCEBRANCH -t|--target TARGETBRANCH

"
}

# source_branch, target_branch
__sync_check_branch() {
    for b in $@; do
        git_check_localbranch "$b"
        if [ $? -ne 0 ]; then
            log_warn "Branch \"$b\" is not in the local repo"; exit
        fi
    done
}

# sync_do_log sourcebr targetbr
sync_do_log() {
    if [ $# -ne 2 ]; then
        sync_usage_log; exit
    fi
    local sourcebr="$1"
    local targetbr="$2"
    __sync_check_branch "$sourcebr" "$targetbr"
    local logs="$(git log $targetbr..$sourcebr --pretty=format:"%h|%an <%ae>|%ai|%s")"
    if [ -z "$logs" ]; then
        return
    fi
    {
    printf "%s|%s|%s|%s\n" "Sha" "Author" "Datetime" "Message"
    printf "%s|%s|%s|%s\n" "------" "------" "------" "------"
    echo "$logs"
    } | format_column "|"
}

sync_usage_diff() {
printf "diff (d): Show the source branch different from the target branch

usage:
    ${PROG} sync diff -s|--source SOURCEBRANCH -t|--target TARGETBRANCH

"
}

# sync_do_diff sourcebr targetbr
sync_do_diff() {
    if [ $# -ne 2 ]; then
        sync_usage_diff; exit
    fi
    local sourcebr="$1"
    local targetbr="$2"
    __sync_check_branch "$sourcebr" "$targetbr"
    git diff $targetbr..$sourcebr
}

sync_usage_version() {
printf "version (v): Show the version of the owner/repo/branch

usage:
    ${PROG} sync v -o|--owner OWNER --repo-list REPOLIST --branch-list BRANCHLIST

params:
    REPOLIST, BRANCHLIST - string list (as: \"a b c\") or list-file

examples:
    ${PROG} sync v -o src-openeuler --repo-list vim --branch-list master
    ${PROG} sync v -o src-openeuler --repo-list \"glibc kernel\" --branch-list openeuler.list

$ cat openeuler.list
openEuler-20.03-LTS
openEuler-20.03-LTS-SP1
openEuler-20.03-LTS-SP2
openEuler-20.03-LTS-SP3
openEuler-20.03-LTS-SP4
openEuler-20.09
openEuler-21.03
openEuler-21.09
openEuler-22.03-LTS
openEuler-22.03-LTS-SP1
openEuler-22.03-LTS-SP2
openEuler-22.03-LTS-SP3
openEuler-22.09
openEuler-23.03
openEuler-23.09
master
\n"
}

sync_do_version() {
    if [[ -z "$1" || -z "$2" || -z "$3" ]]; then
        sync_usage_version; exit
    fi
    local owner="$1"
    local repos="$(get_list "$2")"
    local branches="$(get_list "$3")"

    printf "Repo,Branch,Version,Release\n"
    for r in $repos; do
        for b in $branches; do
            printf "$r,$b"
            local specdata="$(gec_get_contents "$owner" "$r" "$r.spec" "$b")"
            if [ -z "$specdata" ]; then
                printf ",,"
            else
                local v=$(spec_get_version "$specdata")
                local release=$(spec_get_release "$specdata")
                printf ",$v,$release"
            fi
            printf "\n"
        done
    done
}
